package com.wormhole.wormholemanagement.service.impl;

import com.wormhole.wormholemanagement.entity.MedicalInsuranceRecord;
import com.wormhole.wormholemanagement.entity.OperationLog;
import com.wormhole.wormholemanagement.exception.WormException;
import com.wormhole.wormholemanagement.repository.MedicalInsuranceRecordRepository;
import com.wormhole.wormholemanagement.repository.OperationLogRepository;
import com.wormhole.wormholemanagement.repository.OperatorRepository;
import com.wormhole.wormholemanagement.service.MedicalInsuranceRecordService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class MedicalInsuranceRecordServiceImpl implements MedicalInsuranceRecordService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    private final MedicalInsuranceRecordRepository recordRepository;
    private final OperationLogRepository logRepository;

    @Autowired
    private OperatorRepository operatorRepository;

    @Autowired
    public MedicalInsuranceRecordServiceImpl(MedicalInsuranceRecordRepository recordRepository,
                                             OperationLogRepository logRepository) {
        this.recordRepository = recordRepository;
        this.logRepository = logRepository;
    }

    @Override
    @Transactional
    public MedicalInsuranceRecord createRecord(MedicalInsuranceRecord record, Long operatorId) {
        record.setCreatedAt(LocalDateTime.now().toString());
        record.setUpdatedAt(LocalDateTime.now().toString());
        record.setOperatorId(operatorId);
        MedicalInsuranceRecord savedRecord = recordRepository.save(record);

        // Log the operation
        OperationLog log = new OperationLog();
        log.setOperatorId(operatorId);
        log.setOperationType("create");
        log.setTableName("medical_insurance_records");
        log.setRecordId(savedRecord.getRecordId());
        log.setOperationDetails("Created medical insurance record with ID: " + savedRecord.getRecordId());
        log.setOperationTime(LocalDateTime.now());
        logRepository.save(log);

        return savedRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<MedicalInsuranceRecord> createRecordsBatch(List<MedicalInsuranceRecord> records, Long operatorId) {
        // 验证操作员
        operatorRepository.findById(operatorId)
                .orElseThrow(() -> new WormException("操作员不存在"));

        // 批量校验
        validateBatchRecords(records);

        // 使用EntityManager进行批量插入
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        try {
            tx.begin();

            for (int i = 0; i < records.size(); i++) {
                em.persist(records.get(i));

                // 每1000条flush一次
                if (i > 0 && i % 1000 == 0) {
                    em.flush();
                    em.clear();
                }
            }

            tx.commit();
            return records;
        } catch (Exception e) {
            if (tx != null && tx.isActive()) {
                tx.rollback();
            }
            throw new WormException("批量插入失败: " + e.getMessage());
        } finally {
            em.close();
        }
    }
    /**
     * 批量数据校验（私有方法）
     */
    private void validateBatchRecords(List<MedicalInsuranceRecord> records) {
        if (CollectionUtils.isEmpty(records)) {
            throw new WormException("档案列表不能为空");
        }
    }

    @Override
    @Transactional
    public MedicalInsuranceRecord updateRecord(Long id, MedicalInsuranceRecord record, Long operatorId) {
        MedicalInsuranceRecord existingRecord = recordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Record not found with id: " + id));

        // Update fields
        existingRecord.setTitle(record.getTitle());
        existingRecord.setDocumentNumber(record.getDocumentNumber());
        existingRecord.setCreationDate(record.getCreationDate());
        existingRecord.setSocialSecurityCode(record.getSocialSecurityCode());
        existingRecord.setSocialSecurityUnit(record.getSocialSecurityUnit());
        existingRecord.setName(record.getName());
        existingRecord.setIdCard(record.getIdCard());
        existingRecord.setResponsibleParty(record.getResponsibleParty());
        existingRecord.setBoxNumber(record.getBoxNumber());
        existingRecord.setItemNumber(record.getItemNumber());
        existingRecord.setPageNumber(record.getPageNumber());
        existingRecord.setTownship(record.getTownship());
        existingRecord.setHospital(record.getHospital());
        existingRecord.setExtendedData(record.getExtendedData());
        existingRecord.setUpdatedAt(LocalDateTime.now().toString());
        existingRecord.setOperatorId(operatorId);

        MedicalInsuranceRecord updatedRecord = recordRepository.save(existingRecord);

        // Log the operation
        OperationLog log = new OperationLog();
        log.setOperatorId(operatorId);
        log.setOperationType("update");
        log.setTableName("medical_insurance_records");
        log.setRecordId(updatedRecord.getRecordId());
        log.setOperationDetails("Updated medical insurance record with ID: " + updatedRecord.getRecordId());
        log.setOperationTime(LocalDateTime.now());
        logRepository.save(log);

        return updatedRecord;
    }

    @Override
    @Transactional
    public void deleteRecord(Long id, Long operatorId) {
        MedicalInsuranceRecord record = recordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Record not found with id: " + id));

        recordRepository.delete(record);

        // Log the operation
        OperationLog log = new OperationLog();
        log.setOperatorId(operatorId);
        log.setOperationType("delete");
        log.setTableName("medical_insurance_records");
        log.setRecordId(id);
        log.setOperationDetails("Deleted medical insurance record with ID: " + id);
        log.setOperationTime(LocalDateTime.now());
        logRepository.save(log);
    }

    @Override
    public MedicalInsuranceRecord getRecordById(Long id) {
        return recordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Record not found with id: " + id));
    }

    @Override
    public Page<MedicalInsuranceRecord> getAllRecords(Pageable pageable) {
        return recordRepository.findAll(pageable);
    }

    @Override
    public Page<MedicalInsuranceRecord> searchRecords(Specification<MedicalInsuranceRecord> spec, Pageable pageable) {
        return recordRepository.findAll(spec, pageable);
    }
}